#include "impl/files_cleaner_impl.hpp"



namespace alex::utils::impl
{
  files_cleaner_impl::files_cleaner_impl()
    : target_directory_{}
    , entities_to_remove_{}
  { }



  files_cleaner_impl::files_cleaner_impl(std::string_view target_directory)
    : target_directory_{target_directory.data()}
    , entities_to_remove_{}
  {
    check_path(target_directory_);
  }



  void files_cleaner_impl::set_target_directory(const fs::path& target_directory)
  {
    check_path(target_directory);
    target_directory_ = target_directory;
  }



  std::string files_cleaner_impl::current_target_directory() const
  {
    return target_directory_.string();
  }



  std::size_t files_cleaner_impl::remove_all()
  {
    scan_for_files_and_subdirs();

    if (entities_to_remove_.empty())
    {
      return 0;
    }

    std::size_t total_removed_size{0};

    for (auto&& entity : entities_to_remove_)
    {
  #ifdef __USE_BOOST_FILESYSTEM
      boost::system::error_code remove_failed{};
  #endif // FILESYSTEM

      std::size_t entity_size{0};

  #ifdef __USE_BOOST_FILESYSTEM
      if (entity.status().type() != fs::file_type::directory_file && entity.status().type() != fs::file_type::symlink_file)
  #elif defined (__USE_STD_FILESYSTEM)
      if (entity.status().type() != fs::file_type::directory && entity.status().type() != fs::file_type::symlink)
  #endif // FILESYSTEM
      {
        entity_size += fs::file_size(entity);
      }

  #ifdef __USE_BOOST_FILESYSTEM
      fs::remove(entity, remove_failed);
  #elif defined (__USE_STD_FILESYSTEM)
      const bool remove_failed{fs::remove(entity)};
  #endif // FILESYSTEM

      if (!remove_failed)
      {
        total_removed_size += entity_size;
      }
    }

    return total_removed_size;
  }



  std::list<fs::directory_entry> files_cleaner_impl::list_of_entities_to_remove() const
  {
    return entities_to_remove_;
  }



  std::size_t files_cleaner_impl::scan_for_files_and_subdirs()
  {
    for (auto&& entity : fs::recursive_directory_iterator{target_directory_})
    {
      if (entity.path() != "." || entity.path() != "..")
      {
        entities_to_remove_.emplace_front(entity.path());
      }
    }

    return entities_to_remove_.size();
  }



  void files_cleaner_impl::check_path(const fs::path& path)
  {
    if (!fs::is_directory(path))
    {
      throw std::runtime_error{"This is not a directory: " + path.string()};
    }

    if (!fs::exists(path))
    {
      throw std::runtime_error{"No such directory: " + path.string()};
    }
  }
} // namespace alex::utils::impl
